import pymongo
from pyecharts.charts import Line, Bar, Tab
import pyecharts.options as opts


class ChartMaker(object):
    def _get_col_from_db(self, region):
        """连接数据库, 获取region市信息集合"""
        client = pymongo.MongoClient('localhost', 27017)
        database = client['Weather']
        collection = database.get_collection(region)
        return collection

    def get_charts(self, region, district=None):
        """根据是否传入区名称参数district来确定画图方式"""
        start_date, end_date = self._get_weather_date(region)
        if district:
            line, district = self._get_district_line(region, district)
            line.page_title = f'{region}{district} {start_date}-{end_date}'
            return line
        else:
            tab = self._get_region_tab(region)
            tab.page_title = f'{region} {start_date}-{end_date}'
            return tab

    def _get_weather_date(self, region):
        """获取天气预报的日期范围"""
        date_list = list(self._get_col_from_db(region).find_one()['weather_info'].keys())
        return date_list[0].replace('/', '.'), date_list[-1].replace('/', '.')

    def _get_region_tab(self, region):
        """获取region市的空气质量复合图和其各区天气预报折线图组合的tab图"""
        line_list = []  # 各区天气预报图折线图组成的列表
        # 获取空气质量数据
        datas = self._get_col_from_db(region).find()
        pm_avg_datas = []
        aqi_datas = []
        district_x = []
        for data in datas:
            # 组装region市空气质量信息
            pm_avg_datas.append(data['pm_avg'])
            aqi_datas.append(data['aqi'])
            district_x.append(data['district'])

            # 获取各区天气预报折线图
            line_list.append(self._get_district_line(region, data['district']))
        # 获取region市的空气质量复合图
        bar = self._get_region_bar(aqi_datas, district_x, pm_avg_datas)

        # 将 region市的空气质量复合图 和 各区天气预报折线图 组合到一个网页
        tab = Tab()
        tab.add(bar, f"{region}市各区空气质量状况")
        for li_name_list in line_list:
            tab.add(li_name_list[0], f"{li_name_list[1]}区")
        return tab

    def _get_region_bar(self, aqi_datas, district_x, pm_avg_datas):
        """获取数据获取region市各区空气质量状况的bar、line组合图"""
        bar = (
            Bar()
            .add_xaxis(xaxis_data=district_x)
            .add_yaxis(
                series_name="空气质量指数",
                y_axis=aqi_datas,
                label_opts=opts.LabelOpts(is_show=False),
            )
            .extend_axis(
                yaxis=opts.AxisOpts(
                    name="pm2.5浓度",
                    type_="value",
                    axislabel_opts=opts.LabelOpts(formatter="{value} μg/m³"),
                )
            )
            .set_global_opts(
                visualmap_opts=opts.VisualMapOpts(
                    is_piecewise=True,
                    pieces=[
                        {"min": 0, "max": 50, "label": "优", "color": "#289a48"},
                        {"min": 51, "max": 100, "label": "良", "color": "#f9dd2c"},
                        {"min": 101, "max": 150, "label": "轻度污染", "color": "#FF9966"},
                        {"min": 151, "max": 200, "label": "中度污染", "color": "#FF6666"},
                        {"min": 201, "max": 300, "label": "重度污染", "color": "#CC3333"},
                        {"min": 301, "label": "严重污染", "color": "#990033"}
                    ]),
                tooltip_opts=opts.TooltipOpts(
                    is_show=True, trigger="axis", axis_pointer_type="cross"
                ),
                xaxis_opts=opts.AxisOpts(
                    type_="category",
                    axislabel_opts={"interval": "0"},
                    axispointer_opts=opts.AxisPointerOpts(is_show=True, type_="shadow"),
                ),
                yaxis_opts=opts.AxisOpts(
                    name="aqi",
                    type_="value",
                    axislabel_opts=opts.LabelOpts(formatter="{value}"),
                    axistick_opts=opts.AxisTickOpts(is_show=True),
                    splitline_opts=opts.SplitLineOpts(is_show=True),
                ),
            )
        )
        line = (
            Line()
            .add_xaxis(xaxis_data=district_x)
            .add_yaxis(
                series_name="pm2.5浓度",
                yaxis_index=1,
                y_axis=pm_avg_datas,
                label_opts=opts.LabelOpts(is_show=False),
            )
        )
        bar.overlap(line)
        return bar

    def _get_district_line(self, region, district):
        """获取region市district区7天天气预报折线图"""
        collection = self._get_col_from_db(region)
        district_info = collection.find_one({"district": district})
        day_list = []
        max_temp_list = []
        min_temp_list = []
        conditions = []
        for day, weather in district_info['weather_info'].items():
            day_list.append(day)
            max_temp_list.append(weather['max_tpr'])
            min_temp_list.append(weather['min_tpr'])
            conditions.append(weather['conditions'])
        line = Line()
        line.add_xaxis(day_list)
        line.add_yaxis(series_name="最高气温", y_axis=max_temp_list, is_symbol_show=True,
                       markpoint_opts=opts.MarkPointOpts(
                           data=[
                               opts.MarkPointItem(type_="max", name="最大值"),
                               opts.MarkPointItem(type_="min", name="最小值"),
                           ]
                       ),
                       markline_opts=opts.MarkLineOpts(
                           data=[opts.MarkLineItem(type_="average", name="平均值")]
                       ))
        line.add_yaxis(series_name="最低气温", y_axis=min_temp_list, is_symbol_show=True,
                       markpoint_opts=opts.MarkPointOpts(
                           data=[
                               opts.MarkPointItem(type_="max", name="最大值"),
                               opts.MarkPointItem(type_="min", name="最小值"),
                           ]
                       ),
                       markline_opts=opts.MarkLineOpts(
                           data=[opts.MarkLineItem(type_="average", name="平均值")]
                       ))
        line.set_global_opts(yaxis_opts=opts.AxisOpts(name="温度（℃）"),
                             title_opts=opts.TitleOpts(title=f"{region}市{district}区气温变化表"),
                             tooltip_opts=opts.TooltipOpts(trigger="axis"))
        bar = Bar()
        bar.add_xaxis(day_list)
        bar.add_yaxis('天气状况', conditions)
        line.overlap(bar)
        return [line, district]


if __name__ == '__main__':
    # cm = ChartMaker('北京', '西城')
    # for data in cm.get_info_from_db():
    #     print(data['district'])

    cm = ChartMaker()
    chart = cm.get_charts('北京')
    chart.render(f'{chart.page_title}.html')
